package org.linlinjava.litemall.wx.service;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.service.WxPayService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jetbrains.annotations.NotNull;
import org.linlinjava.litemall.core.task.TaskService;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.dao.LitemallMemberOrderMapper;
import org.linlinjava.litemall.db.dao.LitemallMemberRuleMapper;
import org.linlinjava.litemall.db.dao.LitemallUserMemberMapper;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.PayStatusConstant;
import org.linlinjava.litemall.db.util.RentOrderConstant;
import org.linlinjava.litemall.wx.dto.PayInfo;
import org.linlinjava.litemall.wx.task.MemberOrderUnpaidTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Service("member-pay")
public class WxMemberOrderService implements PayProcessor {
    @Resource
    private LitemallMemberRuleMapper memberRuleMapper;
    @Autowired
    private LitemallOrderService orderService;
    @Resource
    private LitemallUserMemberMapper userMemberMapper;
    @Resource
    private LitemallMemberOrderMapper memberOrderMapper;
    @Autowired
    private LitemallMemberRuleService memberRuleService;
    @Autowired
    private LitemallUserMemberService userMemberService;
    @Autowired
    private LitemallRentOrderService rentOrderService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private LitemallUserService userService;
    @Autowired
    private LitemallMemberOrderService memberOrderService;
    @Autowired
    private LitemallDistributionRuleService distributionRuleService;
    @Autowired
    private WxDistributionBenefitService distributionBenefitService;
    @Autowired
    private LitemallMemberTimesService litemallMemberTimesService;

    private final Log logger = LogFactory.getLog(WxMemberOrderService.class);

    /**
     * 提交 支付会员/支付押金 订单
     *
     * @param userId
     * @param body
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public Object submitOrder(Integer userId, String body) {
        JSONObject jsonObject = JSONObject.parseObject(body);
        Integer type = jsonObject.getInteger("type");
        Integer ruleId = jsonObject.getInteger("ruleId");
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        LitemallMemberRule memberRule = memberRuleMapper.selectByPrimaryKey(ruleId);
        if (memberRule == null) {
            return ResponseUtil.fail(400, "未找到该会员");
        }
        /* 如果是提交会员购买订单 */
        BigDecimal originalPrice;
        BigDecimal discount;
        BigDecimal finalPrice;


        switch (type) {
            case 1:
                originalPrice = memberRule.getMemberAmount();
                discount = BigDecimal.ZERO;
                finalPrice = memberRule.getMemberAmount().subtract(discount);
                break;
            case 2:
                originalPrice = memberRule.getDeposit();
                discount = BigDecimal.ZERO;
                finalPrice = originalPrice.subtract(discount);
                break;
            default:
                return ResponseUtil.badArgumentValue();
        }

        LitemallMemberOrder memberOrder = new LitemallMemberOrder();
        memberOrder.setUserId(userId);
        memberOrder.setNickname(userService.findById(userId).getNickname());
        memberOrder.setType(type);
        memberOrder.setMemberRuleId(ruleId);
        memberOrder.setOriginalPrice(originalPrice);
        memberOrder.setDiscount(discount);
        memberOrder.setFinalPrice(finalPrice);
        memberOrder.setMemberOrderSn(orderService.generateOrderSn(userId));
        memberOrder.setAddTime(LocalDateTime.now());
        memberOrder.setUpdateTime(LocalDateTime.now());
        memberOrderMapper.insertSelective(memberOrder);
        // 订单支付超期任务
        taskService.addTask(new MemberOrderUnpaidTask(memberOrder.getId(), 30 * 60 * 1000L));

        return ResponseUtil.ok(memberOrder);
    }

    @NotNull
    private  LitemallMemberTimes getLitemallMemberTimes(Integer userId, LitemallMemberRule memberRule, Long memberOrderId) {
        LitemallMemberTimes memberTimes = new LitemallMemberTimes();
        memberTimes.setUserId(Long.valueOf(userId));
        memberTimes.setMemberId(Long.valueOf(memberRule.getId()));
        memberTimes.setAllTimes(memberRule.getMemberDuration());
        memberTimes.setUseTimes(0);
        memberTimes.setNotUsedTimes(memberTimes.getAllTimes());
        memberTimes.setIsEffective("1");
        memberTimes.setIsDel("0");
        memberTimes.setOrderId(Long.valueOf(memberOrderId));
        return memberTimes;
    }


//    public Map<String, BigDecimal> calculatePaymentAmount(LitemallMemberRule presentRule, LitemallUserMember userMember) {
//        BigDecimal originalPrice = presentRule.getMemberAmount();
//        BigDecimal finalPrice = presentRule.getMemberAmount();
//        BigDecimal discount = BigDecimal.ZERO;
//        Map<String, BigDecimal> map = new HashMap<>();
//        if (userMember == null) {
//            map.put("originalPrice", originalPrice);
//            map.put("discount", discount);
//            map.put("finalPrice", finalPrice);
//            return map;
//        }
//        Integer previousRuleId = userMember.getMemberRuleId();
//        LitemallMemberRule previousRule = memberRuleMapper.selectByPrimaryKey(previousRuleId);
//        Integer presentDurationType = presentRule.getMemberDurationType();
//        Integer previousDurationType = previousRule.getMemberDurationType();
//
//        if (presentDurationType > previousDurationType) {
//            LocalDateTime expirationTime = userMember.getExpirationTime();
//            LocalDateTime now = LocalDateTime.now();
//            Duration leftTimes = Duration.between(now, expirationTime);
//            long leftDays = leftTimes.toDays();
//            discount = previousRule.getMemberAmount().multiply(BigDecimal.valueOf(leftDays * 1.0 / previousRule.getMemberDuration()));
//            finalPrice = presentRule.getMemberAmount().subtract(discount);
//        }
//        map.put("originalPrice", originalPrice);
//        map.put("discount", discount);
//        map.put("finalPrice", finalPrice);
//        return map;
//    }


    public LitemallMemberOrder findByUidAndOid(Integer userId, Integer orderId) {
        LitemallMemberOrderExample example = new LitemallMemberOrderExample();
        example.or().andUserIdEqualTo(userId).andIdEqualTo(orderId).andDeletedEqualTo(false);
        return memberOrderMapper.selectOneByExample(example);
    }

    public LitemallMemberOrder findBySn(String orderSn) {
        LitemallMemberOrderExample example = new LitemallMemberOrderExample();
        example.or().andMemberOrderSnEqualTo(orderSn);
        return memberOrderMapper.selectOneByExample(example);
    }

    @Override
    public PayInfo checkPayInfo(Integer userId, Integer oid) {
        LitemallMemberOrder order = findByUidAndOid(userId, oid);
        if (order == null) {
            return null;
        }
        if (!order.getUserId().equals(userId)) {
            return null;
        }

        // 检测是否能够取消

        PayInfo payInfo = new PayInfo();
        payInfo.setOrderSn(order.getMemberOrderSn());
        payInfo.setPrice(order.getFinalPrice());
        return payInfo;
    }

    @Override
    public Object recordSuccess(String orderSn) {
        return recordSuccess(orderSn, null, null);
    }

    @Override
    public Object recordSuccess(String orderSn, String totalFee, String payId) {
        LitemallMemberOrder order = findBySn(orderSn);
        if (order == null) {
            return WxPayNotifyResponse.fail("订单不存在 sn=" + orderSn);
        }
        if (totalFee == null) {
            totalFee = order.getFinalPrice().toString();
        }
        // 检查这个订单是否已经处理过
        if (!order.getPayStatus().equals(PayStatusConstant.UNPAID)) {
            return WxPayNotifyResponse.success("订单已经处理成功!");
        }

        // 检查支付订单金额
        if (!totalFee.equals(order.getFinalPrice().toString())) {
            return WxPayNotifyResponse.fail(order.getFinalPrice() + " : 支付金额不符合 totalFee=" + totalFee);
        }

        order.setPayId(payId);
        order.setPayTime(LocalDateTime.now());
        order.setPayStatus(PayStatusConstant.HAS_PAID);
        memberOrderMapper.updateByPrimaryKeySelective(order);


        LitemallMemberRule memberRule = memberRuleService.findById(order.getMemberRuleId());
        LitemallUserMember userMember = userMemberService.findByUid(order.getUserId());
        LitemallUser user = userService.findById(order.getUserId());

        if (order.getType().equals(1) && userMember != null) {
            userMember.setExpirationTime(userMember.getExpirationTime().plusDays(memberRule.getMemberDuration()));
            userMember.setUpdateTime(LocalDateTime.now());
            userMemberService.updateById(userMember);
            user.setCostMoney(user.getCostMoney().add(order.getFinalPrice()));
            userService.updateById(user);
        } else {
            if (order.getType().equals(2) && userMember != null) {
                user.setHasPayDeposit(true);
                user.setDeposit(order.getFinalPrice());
                user.setUpdateTime(LocalDateTime.now());
                userService.updateById(user);

            } else if (order.getType().equals(2) && userMember == null) {
                return ResponseUtil.fail(400, "请先开通会员");
            } else {
                userMember = new LitemallUserMember();
                userMember.setMemberRuleId(memberRule.getId());
                userMember.setUserId(order.getUserId());
                userMember.setNickname(user.getNickname());
                userMember.setMemberRuleName(memberRule.getMemberName());
                userMember.setExpirationTime(LocalDateTime.now().plusDays(memberRule.getMemberDuration()));
                userMember.setAddTime(LocalDateTime.now());
                userMember.setEffective("1");
                userMember.setUpdateTime(LocalDateTime.now());
                List<LitemallUserMember> userMembers = userMemberService.findAllByUserId(user.getId());
                /* 检测是否有邀请人 有则走分销*/
                if (userMembers.isEmpty() && user.getPid() != null) {
                    LitemallUser superiorUser = userService.findById(user.getPid());
                    LitemallUserMember superiorUserMember = userMemberService.findByUid(user.getPid());
                    /* 分销 第一种 增加天数 */
                    if (memberRule.getRewardType().equals(1) && superiorUserMember != null) {
                        long benefitDays = memberRule.getRewardDetail().longValue();
                        LocalDateTime expirationTime = superiorUserMember.getExpirationTime();
                        LocalDateTime plusDays = expirationTime.plusDays(benefitDays);
                        superiorUserMember.setExpirationTime(plusDays);
                        userMemberService.updateById(superiorUserMember);
                        superiorUser.setNumberOfInvitations(superiorUser.getNumberOfInvitations() + 1);
                        superiorUser.setInvitationBenefitDays(superiorUser.getInvitationBenefitDays() + memberRule.getRewardDetail().intValue());
                        userService.updateById(superiorUser);
                        LitemallDistributionBenefit distributionBenefit = new LitemallDistributionBenefit();
                        distributionBenefit.setType(1);
                        distributionBenefit.setBeneficiaryUserId(user.getPid());
                        distributionBenefit.setLowerUserId(user.getId());
                        distributionBenefit.setLowerUserName(user.getNickname());
                        distributionBenefit.setDetail((memberRule.getRewardDetail()));
                        distributionBenefitService.create(distributionBenefit);

                    }
                    /* 分销 第二种 增加余额 */
                    else if (memberRule.getRewardType().equals(2) && superiorUserMember != null) {
                        userService.addBalance(superiorUser.getId(), memberRule.getRewardDetail(), Short.valueOf("2"));
                        superiorUser.setNumberOfInvitations(superiorUser.getNumberOfInvitations() + 1);
                        superiorUser.setInvitationBenefitAmount(superiorUser.getInvitationBenefitAmount().add(memberRule.getRewardDetail()));
                        userService.updateById(superiorUser);
                        LitemallDistributionBenefit distributionBenefit = new LitemallDistributionBenefit();
                        distributionBenefit.setType(2);
                        distributionBenefit.setBeneficiaryUserId(user.getPid());
                        distributionBenefit.setLowerUserId(user.getId());
                        distributionBenefit.setLowerUserName(user.getNickname());
                        distributionBenefit.setDetail((memberRule.getRewardDetail()));
                        distributionBenefitService.create(distributionBenefit);
                    }
                }
                userMemberMapper.insertSelective(userMember);
                user.setCostMoney(user.getCostMoney().add(order.getFinalPrice()));
                user.setUserLevel(2);
                userService.updateById(user);
            }
        }
        if (memberRule.getMemberType() == 0){
            LitemallMemberTimes memberTimes = getLitemallMemberTimes(userMember.getUserId(), memberRule, Long.valueOf(userMember.getId()));
            litemallMemberTimesService.insertMemberTimes(memberTimes);
        }
        taskService.removeTask(new MemberOrderUnpaidTask(order.getId(), 600 * 60 * 1000L));
        return WxPayNotifyResponse.success("处理成功!");
    }

    /**
     * 申请退押金
     *
     * @param userId
     * @param memberOrderId
     * @return
     */
    public Object applyRefund(Integer userId, Integer memberOrderId) {
        LitemallMemberOrder memberOrder = memberOrderMapper.selectByPrimaryKey(memberOrderId);
        if (memberOrder == null) {
            return ResponseUtil.fail(400, "该订单不存在");
        }
        if (memberOrder.getPayStatus().equals(PayStatusConstant.UNPAID)) {
            return ResponseUtil.fail(400, "您尚未交押金");
        } else if (memberOrder.getPayStatus().equals(PayStatusConstant.UN_REFUNDED)) {
            return ResponseUtil.fail(400, "后台正在审核中，请耐心等待");
        } else if (memberOrder.getPayStatus().equals(PayStatusConstant.HAS_REFUNDED)) {
            return ResponseUtil.fail(400, "无可退押金");
        }
        LitemallUserMember userMember = userMemberService.findByUid(userId);
        if (userMember != null) {
            return ResponseUtil.fail(400, "您的会员还未到期，请到期后再申请");
        }
        LitemallRentOrder rentOrder = rentOrderService.queryLastOrder(userId);
        if (rentOrder == null || rentOrder.getRentOrderStatus().equals(RentOrderConstant.STATUS_CONFIRM_RETURN) || rentOrder.getRentOrderStatus().equals(RentOrderConstant.STATUS_CANCEL)) {
            memberOrder.setPayStatus(PayStatusConstant.UN_REFUNDED);
            memberOrder.setRefundAmount(memberOrder.getFinalPrice());
            memberOrderMapper.updateByPrimaryKeySelective(memberOrder);
            return ResponseUtil.ok("申请成功，押金审核通过后，三个工作日内原路退回");
        } else {
            return ResponseUtil.fail(400, "申请失败，您还有未归还订单，请先归还订单再申请退押金");
        }

    }

    /**
     * 获取用户押金订单号
     *
     * @param userId
     * @return
     */
    public LitemallMemberOrder getDepositOrder(Integer userId) {
        return memberOrderService.findDepositByUserId(userId);
    }

    /**
     * 获取押金状态 0：未交押金，1：待支付，2：已支付 ，3：申请退款，4：已退款
     *
     * @param userId
     * @return
     */
    public Integer getDepositStatus(Integer userId) {
        LitemallMemberOrder depositOrder = getDepositOrder(userId);
        if (depositOrder == null) {
            return 0;
        } else {
            return depositOrder.getPayStatus();
        }
    }


}
